﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using Domain; 

namespace DAO
{
    public static class UsuarioDAO
    {
        public static Usuario Traer(long username)
        {
            using (IObjectContainer db = Connect.getDataBase())
            {
                try
                {
                    Usuario u = new Usuario();
                    u.UserName = username;
                    IObjectSet user = db.QueryByExample(u);

                    if (!user.HasNext())
                        return null;

                    u = (Usuario)user.Next();
                    Connect.assignId(db, (object)u);
                    return u;
                }
                finally
                {
                    db.Close();
                }
            }
        }

        public static Usuario DesasociarEmpresa(Usuario usr, long idEmpresa)
        {
            Asociacion asoc = usr.AsociacionesActivas.First(delegate(Asociacion a)
            {
                return a.IdEmpresa == idEmpresa &&
                       !a.FechaBajaAsociacion.HasValue;
            });
            asoc.FechaBajaAsociacion = DateTime.Now;
            UsuarioDAO.Guardar(usr);
            return usr;
        }

        public static Usuario DesasociarPublicacion(Usuario usr, long idPublicacion)
        {

            Asociacion asoc = usr.AsociacionesActivas.First(delegate(Asociacion a)
            {
                return a.IdPublicidad == idPublicacion &&
                       !a.FechaBajaAsociacion.HasValue;
            });

            asoc.FechaBajaAsociacion = DateTime.Now;
            UsuarioDAO.Guardar(usr);
            return usr;

        }

        public static Usuario AsociarEmpresa(Usuario usr, long idEmpresa)
        {
            usr = UsuarioDAO.Traer(usr.UserName);

            if (usr.AsociacionesActivas.Exists(
                    delegate(Asociacion a) { 
                        return a.IdEmpresa.HasValue && a.IdEmpresa.Value == idEmpresa; }))
                return usr;

            Asociacion emp = new Asociacion(DateTime.Now, null, null, idEmpresa);
            usr.Asociaciones.Add(emp);
            UsuarioDAO.Guardar(usr);
            return usr;
        }

        public static Usuario AsociarPublicacion(Usuario usr, long idPublicacion)
        {
            usr = UsuarioDAO.Traer(usr.UserName);

            if (usr.AsociacionesActivas.Exists(
                    delegate(Asociacion a) { 
                        return a.IdPublicidad.HasValue && 
                            a.IdPublicidad.Value == idPublicacion; }))
                return usr;

            Asociacion pub = new Asociacion(DateTime.Now, null, idPublicacion, null);
            usr.Asociaciones.Add(pub);
            UsuarioDAO.Guardar(usr);
            Email.goSendPublicacion(idPublicacion,usr);
            return usr;

        }

        public static string RegistrarConsumo(long dni, long pin, long idpublicacion, Empresa emp)
        {
            Usuario usr = UsuarioDAO.Traer(dni);
            if (usr == null)
            {
                return "Los datos del usuario son incorrectos.";
            }

            if (!usr.PIN.HasValue)
            {
                return "El usuario no posee PIN, imposible registrar el consumo.";
            }

            if (usr.PIN.Value != pin)
            {
                return "PIN inválido.";
            }

            List<Publicacion> publicaciones = (from Publicacion pub in emp.Publicaciones
                                                where pub.Id == idpublicacion
                                                select pub).ToList();

            if (publicaciones.Count <= 0 || publicaciones.Count > 1)
            {
                return "Publicación no encontrada.";
            }

            Publicacion p = publicaciones[0];

            if (p.Estado == Publicacion.enum_Publicacion_Estado.Caducada)
            {
                return "La publicación está vencida, imposible continuar.";
            }

            if (p.Estado == Publicacion.enum_Publicacion_Estado.Baja)
            {
                return "La publicación se encuentra dada de baja,imposible continuar";
            }

            if (p.Estado == Publicacion.enum_Publicacion_Estado.Anulada)
            {
                return "La publicación se encuentra anulada,imposible continuar";
            }

            if (!usr.AsociacionesActivas.Exists(delegate (Asociacion a) {return (a.IdPublicidad.HasValue && a.IdPublicidad.Value == p.Id) || 
                                                                                (a.IdEmpresa.HasValue && a.IdEmpresa.Value == emp.UserName);}))
            {
                return "El usuario no está habilitado para hacer consumo de esta publicación.";
            }
            
            usr.Consumos.Add(new Consumo(idpublicacion, DateTime.Now));
            UsuarioDAO.Guardar(usr);
            Email.Send("Felicitaciones, <br /> Has hecho efectivo el uso de tu suscripción \"" + p.Descripcion + "\"", usr.EMail, "¡Consumo realizado!");
            return string.Empty;
        }

        public static bool Guardar(Usuario usuario)
        {
            using (IObjectContainer db = Connect.getDataBase())
            {
                try
                {
                    if (usuario.db4oid.HasValue)
                    {
                        Connect.rebindId(db, (object)usuario);
                    }
                    else
                    {
                        Email.Send("Felicitaciones, a partir de este momento formás parte de Hidden Code 2.0, la mejor red de descuentos, beneficios e información de la región. <br /> Gracias por utilizar nuestros servicios.", usuario.EMail, "¡Bienvenido a Hidden Code 2.0!");
                    }

                    db.Store(usuario);
                    db.Commit();
                }
                finally
                {
                    db.Close();
                }
            }
            return true;
        }

        public static List<Usuario> TraerSeguidoresDe(long? idEmp, long? idPub)
        {
            using (IObjectContainer db = Connect.getDataBase())
            {
                try
                {
                    List<Usuario> seguidores = (from Usuario u in db
                                                from a in u.AsociacionesActivas
                                                where (a.IdEmpresa.HasValue && idEmp.HasValue && a.IdEmpresa.Value == idEmp.Value) ||
                                                      (a.IdPublicidad.HasValue && idPub.HasValue && a.IdPublicidad.Value == idPub.Value)
                                                select u).ToList();

                    Connect.lstAssignId(db, seguidores.AsQueryable().OfType<object>().ToList());

                    return seguidores;
                }
                finally
                {
                    db.Close();
                }
            }
        }
    }
}
